﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;
using Datorgrafik_lab1.Models;

namespace Datorgrafik_lab1.Objects
{
    public abstract class GameObject
    {
        protected GraphicsDevice device;
        protected VertexPositionColor[] vertices;
        protected int[] indices;

        private VertexBuffer vertexBuffer { get; set; }
        private IndexBuffer indexBuffer { get; set; }

        public Quaternion Rotation;
        protected Vector3 Position;
        protected float Scale;

        private Matrix world;
        protected List<GameObject> children = new List<GameObject>();        

        //Models implement geometry
        protected abstract void InitializeModel();

        public virtual void Update()
        {
            this.world = Matrix.Identity * Matrix.CreateScale(this.Scale) * Matrix.CreateFromQuaternion(this.Rotation) * Matrix.CreateTranslation(this.Position);

            foreach (GameObject entity in this.children)
            {
                entity.Update();
            }
        }

        public GameObject(GraphicsDevice graphicsDevice, Vector3 pos, Quaternion rot, float scale)            
        {
            this.device = graphicsDevice;
            InitializeModel();

            this.vertexBuffer = new VertexBuffer(graphicsDevice, typeof(VertexPositionColor), this.vertices.Length, BufferUsage.None);
            this.indexBuffer = new IndexBuffer(graphicsDevice, typeof(int), this.indices.Length, BufferUsage.None);

            this.vertexBuffer.SetData<VertexPositionColor>(this.vertices);
            this.indexBuffer.SetData<int>(this.indices);

            this.Position = pos;
            this.Rotation = rot;
            this.Scale = scale;

            this.world = Matrix.Identity * Matrix.CreateScale(scale) * Matrix.CreateFromQuaternion(this.Rotation) * Matrix.CreateTranslation(this.Position);
        }

        public void Draw(ref BasicEffect effect, ref Matrix parentWorld)
        {
            Matrix newWorld = this.world * parentWorld;
            effect.World = newWorld;
            effect.CurrentTechnique.Passes[0].Apply();

            this.device.SetVertexBuffer(this.vertexBuffer);
            this.device.Indices = this.indexBuffer;
            this.device.DrawIndexedPrimitives(PrimitiveType.TriangleList, 0, 0, this.vertices.Length, 0, this.indices.Length / 3);

            foreach (GameObject gameObject in this.children)
            {
                gameObject.Draw(ref effect, ref newWorld);
            }
        }

        public void AddChild(GameObject child)
        {
            this.children.Add(child);
        }
    }
}
